////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_NETWORKING_LINUX_HEADER_H 
#define __WN_NETWORKING_LINUX_HEADER_H 

#include <WNNetworking/inc/WNNetworkManager.h>

static WN_VOID* WNReadThread(WN_VOID* _networkManager);
static WN_VOID* WNWriteThread(WN_VOID* _networkManager);
static WN_VOID* WNQueueThread(WN_VOID* _networkManager);

enum WNConnectionMessageType {
    eWNConnectionAcceptConnection,
    eWNConnectionSendReady,
    eWNConnectionReadReady,
    eWNConnectionDone
};

WN_VOID AddToReadEPoll(WNConnectionData* _data);
WN_VOID AddToWriteEPoll(WNConnectionData* _data);

class WNConnectionData {
public:
    WNConnectionData(WNNetworking::WNNetworkManager& _manager) :
        mManager(_manager),
        mConnectionHandle(0),
        mSocketHandle(0),
        mReadyToWrite(false),
        mCurrentReadBuffer(_manager),
        mReadHead(0),
        mExpectedData(0),
        mProcessedHead(0),
        mLeftoverData(0),
        mProcessedData(0),
        mBufferWritten(0),
        mBufferChunkCount(0),
        mTotalSent(0),
        mTotalReceived(0)  {
        mCurrentReadBuffer.Clear();
        mReadBuffers.push_back(WNContainers::WNAllocateResource<WNBufferResource>(mManager));
    }
    
    WN_VOID SetConnectionHandle(WNNetworking::WNConnectionHandle _connection) {
        mConnectionHandle = _connection;
    }

    WN_VOID SetSocketDescriptor(WN_INT32 _descriptor) {
        mSocketHandle = _descriptor;
    }

    WN_VOID SetConnectedCallback(const WNContainers::WNCallback2<WN_BOOL, WNNetworking::WNConnectionHandle, const WN_CHAR*>& _callback) {
        mConnectedCallback = _callback;
    }
    WNContainers::WNCallback2<WN_BOOL, WNNetworking::WNConnectionHandle, const WN_CHAR*>& GetConnectionCallback() {
        return(mConnectedCallback);
    }
    WN_VOID AppendSendBuffer(WNNetworking::WNNetworkWriteBuffer& _buff);
    WN_VOID ReadReady();
    WN_VOID WriteReady();
    WN_INT32 GetHandle() {
        return(mSocketHandle);
    }
private:    
    WN_VOID Send();
    WNNetworking::WNConnectionHandle mConnectionHandle;
    WNContainers::WNCallback2<WN_BOOL, WNNetworking::WNConnectionHandle, const WN_CHAR*> mConnectedCallback;
    WN_UINT32 mCallbackFunction;
    WNConcurrency::WNSpinLock mSendBufferLock;
    WN_INT32 mSocketHandle;
    WN_BOOL  mReadyToWrite;
    WNNetworking::WNNetworkManager& mManager;
    WNNetworking::WNNetworkReadBuffer mCurrentReadBuffer;
    std::deque<WNContainers::WNResourcePointer<WNNetworking::WNBufferResource> > mReadBuffers;
    std::deque<WNNetworking::WNNetworkWriteBuffer > mSendBuffers;
    WN_SIZE_T mReadHead;
    WN_SIZE_T mExpectedData;
    WN_SIZE_T mProcessedHead;
    WN_SIZE_T mProcessedData;
    WN_CHAR mLeftover[8];
    WN_SIZE_T mLeftoverData;
    WN_SIZE_T mBufferWritten;
    WN_SIZE_T mBufferChunkCount;
    WN_SIZE_T mTotalSent;
    WN_SIZE_T mTotalReceived;
};

struct WNConnectionMessage{
    WNConnectionMessageType mType;
    WNConnectionData* mData;
};

enum WNInitializationStates {
    WN_NOT_STARTED,
    WN_THREADS_CREATED,
    WN_LISTEN_THREAD_CREATED,
    WN_INITIALIZATION_COMPLETE,
    WN_EPOLL_READ_CREATED,
    WN_EPOLL_WRITE_CREATED,
    WN_EVENTS_CREATED
};

private:

WN_VOID AddMessage(const WNConnectionMessage& _message);
WN_VOID AcceptConnection(WNConnectionData* _acceptSocket);
 

WNInitializationStates mInitializationState;

std::deque<WNConnectionMessage> mMessages;
std::vector<WNConnectionData*>           mListenSockets;
WNConcurrency::WNSpinLock       mHandleLock;
WNConcurrency::WNSpinLock       mQueueLock;
WNConcurrency::WNSpinLock       mListenLock;
WNConcurrency::WNThread*        mReadThread;
WNConcurrency::WNThread*        mWriteThread;
WN_INT32                        mReadEPollInstance;
WN_INT32                        mWriteEPollInstance;
WN_BOOL                         mShuttingDown;

#endif//__WN_NETWORKING_LINUX_HEADER_H
